﻿using System;
using Slf.Formatters;


namespace Slf.Samples.ImplementingILogger
{

  /// <summary>
  /// Writes colored output to the console. This implementation could be much shorter
  /// if the class derived from LoggerBase instead.
  /// </summary>
  public class ColoredConsoleLogger : ILogger
  {
    //ALSO LOOK AT THE NEXT SAMPLE - IMPLEMENTING ILOGGER IS TEDIOUS, AND IT WOULD HAVE BEEN
    //MUCH EASIER TO JUST DERIVE FROM A BASE CLASS!


    /// <summary>
    /// The logger's name.
    /// </summary>
    public string Name { get; set; }

    #region Debug

    /// <summary>
    /// Logs an arbitrary object with the <see cref="LogLevel.Debug"/> level. 
    /// </summary>
    /// <param name="obj">The message object to log, which will be converted
    /// into a string during logging.</param>
    public void Debug(object obj)
    {
      Log(LogLevel.Debug, (obj ?? "").ToString());
    }


    /// <summary>
    /// Logs a debug message (<see cref="LogLevel.Debug"/>).
    /// </summary>
    /// <param name="message">The message to log.</param>
    public void Debug(string message)
    {
      Log(LogLevel.Debug, message);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Debug"/> level. 
    /// </summary>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Debug(string format, params object[] args)
    {
      Log(LogLevel.Debug, format, args);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Debug"/> level. 
    /// </summary>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Debug(IFormatProvider provider, string format, params object[] args)
    {
      Log(LogLevel.Debug, provider, format, args);
    }


    /// <summary>
    /// Logs an exception with a logging level of <see cref="LogLevel.Debug"/>.
    /// </summary>
    /// <param name="exception">The exception to log.</param>
    public void Debug(Exception exception)
    {
      Log(LogLevel.Debug, exception);
    }


    /// <summary>
    /// Logs an exception with an additional message with a logging level of
    /// <see cref="LogLevel.Debug"/>.
    /// </summary>
    /// <param name="exception"> The exception to log.</param>
    /// <param name="message">Additional information regarding the
    /// logged exception.</param>
    public void Debug(Exception exception, string message)
    {
      Log(LogLevel.Debug, exception, message);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Debug"/> level. 
    /// </summary>
    /// <param name="exception">The exception to log </param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Debug(Exception exception, string format, params object[] args)
    {
      Log(LogLevel.Debug, exception, format, args);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Debug"/> level. 
    /// </summary>
    /// <param name="exception">The exception to log.</param>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Debug(Exception exception, string format, IFormatProvider provider, params object[] args)
    {
      Log(LogLevel.Debug, exception, provider, format, args);
    }

    #endregion

    #region Info

    /// <summary>
    /// Logs an arbitrary object with the <see cref="LogLevel.Info"/> level. 
    /// </summary>
    /// <param name="obj">The message object to log, which will be converted
    /// into a string during logging.</param>
    public void Info(object obj)
    {
      Log(LogLevel.Info, (obj ?? "").ToString());
    }


    /// <summary>
    /// Logs an informational message (<see cref="LogLevel.Info"/>).
    /// </summary>
    /// <param name="message">The message to log.</param>
    public void Info(string message)
    {
      Log(LogLevel.Info, message);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Info"/> level. 
    /// </summary>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Info(string format, params object[] args)
    {
      Log(LogLevel.Info, format, args);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Info"/> level. 
    /// </summary>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Info(IFormatProvider provider, string format, params object[] args)
    {
      Log(LogLevel.Info, provider, format, args);
    }


    /// <summary>
    /// Logs an exception with a logging level of <see cref="LogLevel.Info"/>.
    /// </summary>
    /// <param name="exception">The exception to log.</param>
    public void Info(Exception exception)
    {
      Log(LogLevel.Info, exception);
    }


    /// <summary>
    /// Logs an exception with an additional message with a logging level of
    /// <see cref="LogLevel.Info"/>.
    /// </summary>
    /// <param name="exception"> The exception to log.</param>
    /// <param name="message">Additional information regarding the
    /// logged exception.</param>
    public void Info(Exception exception, string message)
    {
      Log(LogLevel.Info, exception, message);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Info"/> level. 
    /// </summary>
    /// <param name="exception">The exception to log </param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Info(Exception exception, string format, params object[] args)
    {
      Log(LogLevel.Info, exception, format, args);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Info"/> level. 
    /// </summary>
    /// <param name="exception">The exception to log.</param>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Info(Exception exception, string format, IFormatProvider provider, params object[] args)
    {
      Log(LogLevel.Info, exception, provider, format, args);
    }

    #endregion

    #region Warn

    /// <summary>
    /// Logs an arbitrary object with the <see cref="LogLevel.Warn"/> level. 
    /// </summary>
    /// <param name="obj">The message object to log, which will be converted
    /// into a string during logging.</param>
    public void Warn(object obj)
    {
      Log(LogLevel.Warn, (obj ?? "").ToString());
    }


    /// <summary>
    /// Logs a warning message (<see cref="LogLevel.Warn"/>).
    /// </summary>
    /// <param name="message">The message to log.</param>
    public void Warn(string message)
    {
      Log(LogLevel.Warn, message);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Warn"/> level. 
    /// </summary>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Warn(string format, params object[] args)
    {
      Log(LogLevel.Warn, format, args);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Warn"/> level. 
    /// </summary>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Warn(IFormatProvider provider, string format, params object[] args)
    {
      Log(LogLevel.Warn, provider, format, args);
    }


    /// <summary>
    /// Logs an exception with a logging level of <see cref="LogLevel.Warn"/>.
    /// </summary>
    /// <param name="exception">The exception to log.</param>
    public void Warn(Exception exception)
    {
      Log(LogLevel.Warn, exception);
    }


    /// <summary>
    /// Logs an exception with an additional message with a logging level of
    /// <see cref="LogLevel.Warn"/>.
    /// </summary>
    /// <param name="exception"> The exception to log.</param>
    /// <param name="message">Additional information regarding the
    /// logged exception.</param>
    public void Warn(Exception exception, string message)
    {
      Log(LogLevel.Warn, exception, message);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Warn"/> level. 
    /// </summary>
    /// <param name="exception">The exception to log </param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Warn(Exception exception, string format, params object[] args)
    {
      Log(LogLevel.Warn, exception, format, args);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Warn"/> level. 
    /// </summary>
    /// <param name="exception">The exception to log.</param>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Warn(Exception exception, string format, IFormatProvider provider, params object[] args)
    {
      Log(LogLevel.Warn, exception, provider, format, args);
    }

    #endregion

    #region Error

    /// <summary>
    /// Logs an arbitrary object with the <see cref="LogLevel.Error"/> level. 
    /// </summary>
    /// <param name="obj">The message object to log, which will be converted
    /// into a string during logging.</param>
    public void Error(object obj)
    {
      Log(LogLevel.Error, (obj ?? "").ToString());
    }


    /// <summary>
    /// Logs an error message (<see cref="LogLevel.Error"/>).
    /// </summary>
    /// <param name="message">The message to log.</param>
    public void Error(string message)
    {
      Log(LogLevel.Error, message);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Error"/> level. 
    /// </summary>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Error(string format, params object[] args)
    {
      Log(LogLevel.Error, format, args);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Error"/> level. 
    /// </summary>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Error(IFormatProvider provider, string format, params object[] args)
    {
      Log(LogLevel.Error, provider, format, args);
    }


    /// <summary>
    /// Logs an exception with a logging level of <see cref="LogLevel.Error"/>.
    /// </summary>
    /// <param name="exception">The exception to log.</param>
    public void Error(Exception exception)
    {
      Log(LogLevel.Error, exception);
    }


    /// <summary>
    /// Logs an exception with an additional message with a logging level of
    /// <see cref="LogLevel.Error"/>.
    /// </summary>
    /// <param name="exception"> The exception to log.</param>
    /// <param name="message">Additional information regarding the
    /// logged exception.</param>
    public void Error(Exception exception, string message)
    {
      Log(LogLevel.Error, exception, message);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Error"/> level. 
    /// </summary>
    /// <param name="exception">The exception to log </param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Error(Exception exception, string format, params object[] args)
    {
      Log(LogLevel.Error, exception, format, args);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Error"/> level. 
    /// </summary>
    /// <param name="exception">The exception to log.</param>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Error(Exception exception, string format, IFormatProvider provider, params object[] args)
    {
      Log(LogLevel.Error, exception, provider, format, args);
    }

    #endregion

    #region Fatal

    /// <summary>
    /// Logs an arbitrary object with the <see cref="LogLevel.Fatal"/> level. 
    /// </summary>
    /// <param name="obj">The message object to log, which will be converted
    /// into a string during logging.</param>
    public void Fatal(object obj)
    {
      Log(LogLevel.Fatal, (obj ?? "").ToString());
    }


    /// <summary>
    /// Logs a fatal error message (<see cref="LogLevel.Fatal"/>).
    /// </summary>
    /// <param name="message">The message to log.</param>
    public void Fatal(string message)
    {
      Log(LogLevel.Fatal, message);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Fatal"/> level. 
    /// </summary>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Fatal(string format, params object[] args)
    {
      Log(LogLevel.Fatal, format, args);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Fatal"/> level. 
    /// </summary>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Fatal(IFormatProvider provider, string format, params object[] args)
    {
      Log(LogLevel.Fatal, provider, format, args);
    }


    /// <summary>
    /// Logs an exception with a logging level of <see cref="LogLevel.Fatal"/>.
    /// </summary>
    /// <param name="exception">The exception to log.</param>
    public void Fatal(Exception exception)
    {
      Log(LogLevel.Fatal, exception);
    }


    /// <summary>
    /// Logs an exception with an additional message with a logging level of
    /// <see cref="LogLevel.Fatal"/>.
    /// </summary>
    /// <param name="exception"> The exception to log.</param>
    /// <param name="message">Additional information regarding the
    /// logged exception.</param>
    public void Fatal(Exception exception, string message)
    {
      Log(LogLevel.Fatal, exception, message);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Fatal"/> level. 
    /// </summary>
    /// <param name="exception">The exception to log </param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Fatal(Exception exception, string format, params object[] args)
    {
      Log(LogLevel.Fatal, exception, format, args);
    }


    /// <summary>
    /// Logs a formatted message string with the <see cref="LogLevel.Fatal"/> level. 
    /// </summary>
    /// <param name="exception">The exception to log.</param>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public void Fatal(Exception exception, string format, IFormatProvider provider, params object[] args)
    {
      Log(LogLevel.Fatal, exception, provider, format, args);
    }

    #endregion


    #region Log

    /// <summary>
    /// Logs a formatted message on a given logging level. 
    /// </summary>
    /// <param name="level">The logging level which is used to indicate severity,
    /// or for for filtering the information .</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public virtual void Log(LogLevel level, string format, params object[] args)
    {
      Log(level, String.Format(format, args));
    }


    /// <summary>
    /// Logs a formatted message on a given logging level.
    /// </summary>
    /// <param name="level">The logging level which is used to indicate severity,
    /// or for for filtering the information .</param>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public virtual void Log(LogLevel level, IFormatProvider provider, string format, params object[] args)
    {
      Log(level, String.Format(provider, format, args));
    }


    /// <summary>
    /// Logs a message on a given logging level.
    /// </summary>
    /// <param name="level">The logging level which is used to indicate severity,
    /// or for for filtering the information .</param>
    /// <param name="message"> The message to log.</param>
    public virtual void Log(LogLevel level, string message)
    {
      LogItem item = new LogItem { LogLevel = level, Message = message };
      Log(item);
    }


    /// <summary>
    /// Logs an exception with on a given logging level.
    /// </summary>
    /// <param name="level">The logging level which is used to indicate severity,
    /// or for for filtering the information .</param>
    /// <param name="exception">The exception to log.</param>
    public virtual void Log(LogLevel level, Exception exception)
    {
      Log(level, exception, String.Empty);
    }


    /// <summary>
    /// Logs an exception along with a formatted message string on a given logging level.
    /// </summary>
    /// <param name="level">The logging level which is used to indicate severity,
    /// or for for filtering the information .</param>
    /// <param name="exception">The exception to log </param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public virtual void Log(LogLevel level, Exception exception, string format, params object[] args)
    {
      string message = String.Format(format, args);
      Log(level, exception, message);
    }


    /// <summary>
    /// Logs an exception along with a formatted message string on a given logging level.
    /// </summary>
    /// <param name="level">The logging level which is used to indicate severity,
    /// or for filtering the information .</param>
    /// <param name="exception">The exception to log.</param>
    /// <param name="provider">An <see cref="IFormatProvider"/> which provides
    /// culture-specific formatting capabilities.</param>
    /// <param name="format">A composite format string that contains placeholders for the
    /// arguments.</param>
    /// <param name="args">An <see cref="object"/> array containing zero or more objects
    /// to format.</param>
    public virtual void Log(LogLevel level, Exception exception, IFormatProvider provider, string format,
                            params object[] args)
    {
      string message = String.Format(provider, format, args);
      Log(level, exception, message);
    }


    /// <summary>
    /// Logs an exception along with a message string on a given logging level.
    /// </summary>
    /// <param name="level">The logging level which is used to indicate severity,
    /// or for for filtering the information .</param>
    /// <param name="exception"> The exception to log.</param>
    /// <param name="message">Additional information regarding the
    /// logged exception.</param>
    public virtual void Log(LogLevel level, string message, Exception exception)
    {
      LogItem item = new LogItem { LogLevel = level, Message = message };
      item.Exception = exception;

      Log(item);
    }

    #endregion


    /// <summary>
    /// Creates a new log entry based on a given log item.
    /// </summary>
    /// <param name="item">Encaspulates logging information.</param>
    /// <exception cref="ArgumentNullException">If <paramref name="item"/>
    /// is a null reference.</exception>
    public void Log(LogItem item)
    {
      if (item == null) throw new ArgumentNullException("item");

      switch (item.LogLevel)
      {
        case LogLevel.Info:
          Console.ForegroundColor = ConsoleColor.Green;
          break;
        case LogLevel.Warn:
          Console.ForegroundColor = ConsoleColor.Cyan;
          break;
        case LogLevel.Error:
          Console.ForegroundColor = ConsoleColor.Yellow;
          break;
        case LogLevel.Fatal:
          Console.ForegroundColor = ConsoleColor.Red;
          break;
        default:
          Console.ResetColor();
          break;
      }


      string loggedText = SimpleLogItemFormatter.Instance.FormatItem(item);
      Console.Out.WriteLine(loggedText);
      Console.ResetColor();
    }


  }
}
